home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 4 / Apprentice-Release4.iso / Source Code / Libraries / Graphic Elements 3 / GESound / GESound.c < prev    next >
Text File  |  1995-08-24  |  9KB  |  322 lines

  1. /*
  2.     GESound.c
  3.     
  4.     Asynch sound player for use with Graphic Elements
  5.     
  6.     Requires Sound Manager 3.0 or later
  7.     
  8.     Copyright 1995 by Al Evans. All rights reserved.
  9.     
  10.     3/10/95
  11.     
  12. */
  13.  
  14. #include "GESound.h"
  15.  
  16. typedef struct geSEntry *GESoundLEntryPtr;
  17. typedef struct geSEntry {
  18.     GESoundLEntryPtr    nextEntry;
  19.     short                resID;
  20.     short                nUsers;
  21.     long                flags;        // Keep in memory, etc.
  22.     Handle                sound;
  23. } GESoundListEntry;
  24.  
  25. static pascal void SndDoneProc(SndChannelPtr channel, SndCommand *cmd);
  26.  
  27. GESoundPtr GEInitSounds(short nSoundChannels)
  28. {
  29.     GESoundPtr    sound;
  30.     long        size = sizeof(LHeaderPtr) + sizeof(long) + 
  31.                         (2 * sizeof(short)) + (nSoundChannels * sizeof(GESndChan));
  32.     short        sndCount;
  33.     OSErr        err;
  34.     
  35.     if (SndSoundManagerVersion().majorRev < 3)
  36.         return nil;
  37.     sound = (GESoundPtr) NewPtrClear(size);
  38.     if (sound == nil)
  39.         return nil;
  40.     sound->soundsLoaded = InitList(20, sizeof(GESoundListEntry));
  41.     if (sound->soundsLoaded == nil)
  42.         return nil;
  43.     sound->soundCallBack = NewSndCallBackProc(SndDoneProc);
  44.     sound->nCurrent = 0;
  45.     sound->soundEnabled = 1;
  46.     
  47.     for (sndCount = 0; sndCount < nSoundChannels; sndCount++)
  48.     {
  49.         err = SndNewChannel(&sound->soundChannel[sndCount].channel, 
  50.                             sampledSynth, initMono, sound->soundCallBack);
  51.         if (err != noErr)
  52.             break;
  53.         sound->soundChannel[sndCount].priority = -1;
  54.         sound->soundChannel[sndCount].sndNum = 0;
  55.         sound->nChannels++;        // Only count the ones that actually get created!
  56.     }
  57.     if (sound->nChannels == 0)
  58.         goto abort;
  59.     return sound;
  60.     
  61. abort:
  62.     if (sound != nil) {
  63.         if (sound->soundsLoaded != nil)
  64.             DeleteList(sound->soundsLoaded);
  65.         for (sndCount = 0; sndCount < sound->nChannels; sndCount++) {
  66.             if (sound->soundChannel[sndCount].channel != nil)
  67.                 SndDisposeChannel(sound->soundChannel[sndCount].channel, true);
  68.         }
  69.         DisposePtr((Ptr) sound);
  70.     }
  71.     return nil;    
  72. }
  73.  
  74. Boolean SndCompare(Ptr snd1, Ptr snd2)
  75. {
  76.     return (((GESoundLEntryPtr) snd2)->resID > ((GESoundLEntryPtr) snd1)->resID );
  77. }
  78.  
  79. GESoundLEntryPtr GEGetSoundsRec(GESoundPtr sounds, short sndResID)
  80. {
  81.     GESoundLEntryPtr thisSnd = (GESoundLEntryPtr) sounds->soundsLoaded->listHead;
  82.     while (thisSnd != nil) {
  83.         if (thisSnd->resID == sndResID) 
  84.             break;
  85.         thisSnd = (GESoundLEntryPtr) thisSnd->nextEntry;
  86.     }
  87.     return thisSnd;
  88. }
  89.  
  90. GESoundLEntryPtr GELoadSound(GESoundPtr sounds, short sndResID)
  91. {
  92.     Handle sndHandle = nil;
  93.     GESoundLEntryPtr thisSnd = GEGetSoundsRec(sounds, sndResID);
  94.     if (thisSnd == nil) {
  95.         // Need to load (& lock??) it
  96.         sndHandle =  (Handle) GetResource('snd ', sndResID);
  97.         if (sndHandle == nil)
  98.             return nil;
  99.         MoveHHi(sndHandle);
  100.         HLock(sndHandle);
  101.         thisSnd = (GESoundLEntryPtr) AllocateEntry(sounds->soundsLoaded);
  102.         thisSnd->resID = sndResID;
  103.         thisSnd->nUsers = 0;
  104.         thisSnd->flags = 0;
  105.         thisSnd->sound = sndHandle;
  106.         InsertEntry(sounds->soundsLoaded, (LMemberPtr) thisSnd, SndCompare);
  107.     }
  108.     return thisSnd;
  109. }
  110.  
  111. void GEReleaseChannel(GESoundPtr sounds, short chanIndex);
  112.  
  113. GESndChanPtr GEAllocChannel(GESoundPtr sounds, short priority)
  114. {
  115.     GESndChanPtr    channel = nil;
  116.     short            chanCt;
  117.     OSErr            err;
  118.     
  119.     // Find an unused channel
  120.     for (chanCt = 0; chanCt < sounds->nChannels; chanCt++) {
  121.         if (sounds->soundChannel[chanCt].priority == -1) {
  122.             if (sounds->soundChannel[chanCt].sndNum != 0) 
  123.                 GEReleaseChannel(sounds, chanCt);
  124.             channel = &sounds->soundChannel[chanCt];
  125.             break;
  126.         }
  127.     }
  128.     // Find channel with priority < new priority and stop sound
  129.     if (channel == nil) {
  130.         for (chanCt = 0; chanCt < sounds->nChannels; chanCt++) {
  131.             if (priority >= sounds->soundChannel[chanCt].priority) {
  132.                 GEStopOneSound(sounds, sounds->soundChannel[chanCt].sndNum);
  133.                 GEReleaseChannel(sounds, chanCt);
  134.                 channel = &sounds->soundChannel[chanCt];
  135.                 break;
  136.             }
  137.         }
  138.     }
  139.     return channel;
  140. }
  141.  
  142. void GEHoldSound(GESoundPtr sounds, short sndResID, Boolean keepInMemory)
  143. {
  144.     if (keepInMemory) {
  145.         GESoundLEntryPtr thisSnd = GELoadSound(sounds, sndResID);
  146.         if (thisSnd != nil)
  147.             thisSnd->flags |= 1;
  148.     }
  149.     else {
  150.         GESoundLEntryPtr thisSnd = GEGetSoundsRec(sounds, sndResID);
  151.         if (thisSnd != nil)
  152.             thisSnd->flags &= ~1;
  153.     }
  154. }
  155.  
  156. OSErr GEScheduleSound(GESoundPtr sounds, short sndResID, short priority, 
  157.                                 unsigned long msDelay)
  158. {
  159.     // If sound not in memory, load it
  160.     GESoundLEntryPtr thisSnd = GELoadSound(sounds, sndResID);
  161.     GESndChanPtr    channel = nil;
  162.     OSErr    err = noErr;
  163.     
  164.     if (thisSnd == nil)
  165.         return ResError();     // ??
  166.     channel = GEAllocChannel(sounds, priority);
  167.     if (channel == nil)
  168.         return badChannel;
  169.     sounds->nCurrent += 1;
  170. //    thisSnd->flags |= keepInMemory;    // ??
  171.     thisSnd->nUsers += 1;
  172.     channel->playTime = TickCount() + (msDelay/16);
  173.     channel->priority = priority;
  174.     channel->sndNum = sndResID;
  175.     return noErr;
  176. }
  177.  
  178. void GEnableSound(GESoundPtr sounds, Boolean enableIt)
  179. {
  180.     sounds->soundEnabled = enableIt;
  181.     if ((!enableIt)  && (sounds->nCurrent > 0))
  182.         GEStopAllSounds(sounds);
  183. }
  184.  
  185. void GEReleaseChannel(GESoundPtr sounds, short chanIndex)
  186. {
  187.     GESndChanPtr    channel = &sounds->soundChannel[chanIndex];
  188.     GESoundLEntryPtr thisSnd = GEGetSoundsRec(sounds, channel->sndNum);
  189.     if (thisSnd == nil)
  190.         return;
  191.     thisSnd->nUsers -= 1;
  192.     if ((thisSnd->nUsers == 0) && ((thisSnd->flags & 1) == 0)) {
  193.         ReleaseResource(thisSnd->sound);
  194.         DeleteEntry(sounds->soundsLoaded, (LMemberPtr) thisSnd);
  195.     }
  196.     channel->sndNum = 0;
  197.     sounds->nCurrent -= 1;
  198. }
  199.  
  200. void GEPlaySndNow(GESoundPtr sounds, GESndChanPtr chan)
  201. {
  202.     GESoundLEntryPtr thisSnd = GEGetSoundsRec(sounds, chan->sndNum);
  203.     OSErr err = noErr;
  204.     
  205.     if (thisSnd == nil)
  206.         return;
  207.     
  208.     err = SndPlay(chan->channel, (SndListHandle) thisSnd->sound, true );
  209.     if (err == noErr) {
  210.         SndCommand cmd;
  211.         cmd.cmd = callBackCmd;
  212.         cmd.param2 = (long) chan;
  213.         err = SndDoCommand(chan->channel, &cmd, false);
  214.     }
  215.     
  216. }
  217.  
  218. void GESoundMaintenance(GESoundPtr sounds)
  219. {
  220.     unsigned long currTime = TickCount();
  221.     short    chanCt;
  222.     // Dispose used sounds, start those that need to play now
  223.     for (chanCt = 0; chanCt < sounds->nChannels; chanCt++) {
  224.         if ((sounds->soundChannel[chanCt].sndNum != 0) &&        // Has a sound &&
  225.             (sounds->soundChannel[chanCt].priority == -1)) {    // Finished playing
  226.             GEReleaseChannel(sounds, chanCt);
  227.             
  228.         }
  229.         else {
  230.             unsigned long playTime = sounds->soundChannel[chanCt].playTime;
  231.             if ((playTime != 0) && (currTime >= playTime)) {
  232.                 if (sounds->soundEnabled)                    // Start sound...
  233.                     GEPlaySndNow(sounds, &sounds->soundChannel[chanCt]);
  234.                 else                                        // Allow it to be unloaded
  235.                     sounds->soundChannel[chanCt].priority =  -1;
  236.                 sounds->soundChannel[chanCt].playTime = 0;
  237.             }
  238.         }
  239.     }
  240. }
  241.  
  242. Boolean GESoundPlaying(GESoundPtr sounds, short sndResID)
  243. {
  244.     short    chanCt;
  245.     for (chanCt = 0; chanCt < sounds->nChannels; chanCt++) {
  246.         if (sounds->soundChannel[chanCt].sndNum == sndResID) {
  247.             return (sounds->soundChannel[chanCt].priority != -1);
  248.         }
  249.     }
  250.     return false;
  251. }
  252.  
  253. void GEStopOneSound(GESoundPtr sounds, short sndResID)
  254. {
  255.     short    chanCt;
  256.     for (chanCt = 0; chanCt < sounds->nChannels; chanCt++) {
  257.         if (sounds->soundChannel[chanCt].sndNum == sndResID) {
  258.             SndCommand    cmd;
  259.             OSErr    err;
  260.             
  261.             cmd.cmd = quietCmd;
  262.             cmd.param1 = 0;
  263.             cmd.param2 = 0;
  264.             err = SndDoImmediate( sounds->soundChannel[chanCt].channel, &cmd );
  265.             cmd.cmd = flushCmd;
  266.             err = SndDoImmediate( sounds->soundChannel[chanCt].channel, &cmd );
  267.             sounds->soundChannel[chanCt].priority = -1;
  268.             return;
  269.         }
  270.     }
  271. }
  272.  
  273. void GEStopAllSounds(GESoundPtr sounds)
  274. {
  275.     short    chanCt;
  276.     for (chanCt = 0; chanCt < sounds->nChannels; chanCt++) {
  277.         if (sounds->soundChannel[chanCt].priority != -1) {
  278.             SndCommand    cmd;
  279.             OSErr    err;
  280.             
  281.             cmd.cmd = quietCmd;
  282.             cmd.param1 = 0;
  283.             cmd.param2 = 0;
  284.             err = SndDoImmediate( sounds->soundChannel[chanCt].channel, &cmd );
  285.             cmd.cmd = flushCmd;
  286.             err = SndDoImmediate( sounds->soundChannel[chanCt].channel, &cmd );
  287.             sounds->soundChannel[chanCt].priority = -1;
  288.             return;
  289.         }
  290.     }
  291.     GESoundMaintenance(sounds);
  292. }
  293.  
  294. void GEDisposeSounds(GESoundPtr sounds)
  295. {
  296.     GESoundLEntryPtr thisSnd = (GESoundLEntryPtr) sounds->soundsLoaded->listHead;
  297.     short    sndCount;
  298.     
  299.     GEStopAllSounds(sounds);
  300.     
  301.     while (thisSnd != nil) {
  302.         if (thisSnd->sound != nil)
  303.             ReleaseResource(thisSnd->sound);
  304.         thisSnd = (GESoundLEntryPtr) thisSnd->nextEntry;
  305.     }
  306.     DeleteList(sounds->soundsLoaded);
  307.     
  308.     DisposeRoutineDescriptor((UniversalProcPtr) sounds->soundCallBack);
  309.     for (sndCount = 0; sndCount < sounds->nChannels; sndCount++) {
  310.         if (sounds->soundChannel[sndCount].channel != nil)
  311.             SndDisposeChannel(sounds->soundChannel[sndCount].channel, true);
  312.     }
  313.     DisposePtr((Ptr) sounds);
  314.     
  315. }
  316.  
  317. static pascal void SndDoneProc(SndChannelPtr channel, SndCommand *cmd)
  318. {
  319.     GESndChanPtr    geChannel = (GESndChanPtr) cmd->param2;
  320.     geChannel->priority = -1;
  321. }
  322.